#pragma unmanaged

namespace UnManaged
{
#	include <System.hpp>
#	include <Events.hpp>
#	include <Module.hpp>

#	include <IDK.hpp>

#	include <ModuleManager.hpp>

#	include <Convert.hpp>

	/*-------------------------------------------------------------------------
	| TModuleManager
	| ------------
	| 
	---------------------------------------------------------------------------*/
	TModuleManager::TModuleManager()
		:
		mModules(new SortList<RefModule>::Create(new TSortModule))
	{
		//Prepare module
		Array<String> modulesName = new Array<String>::Create();
		{
			String temp = "Core.module";
			modulesName->Add(temp);
		}
		{
			String temp = "RenderContextGL.module";
			modulesName->Add(temp);
		}

		Array<RefModule> modules = LoadModules(modulesName);

		for(Array<RefModule>::Iterator it = modules->Begin(), end = modules->End(); it!=end; ++it)
		{
			mModules->Add(*it);
		}
	}

	//-------------------------------------------------------
	// Init
	//-------------------------------------------------------
	void TModuleManager::Init(void)
	{
		DoInit();
	}

	//-------------------------------------------------------
	// Start
	//-------------------------------------------------------
	void TModuleManager::Start(void)
	{
		DoStart();
	}

	//-------------------------------------------------------
	// Stop
	//-------------------------------------------------------
	void TModuleManager::Stop(void)
	{
		DoFinish();
	}

	//-------------------------------------------------------
	// Update
	//-------------------------------------------------------
	void TModuleManager::Update(float dt)
	{
		DoUpdate(dt);
	}

	//-------------------------------------------------------
	// Sort
	//-------------------------------------------------------
	bool TModuleManager::TSortModule::Sort(RefModule item1, RefModule item2)
	{
		return item1->GetInitializeType() < item2->GetInitializeType();
	}

	//-------------------------------------------------------
	// DoFinish
	//-------------------------------------------------------
	void TModuleManager::DoFinish(void)
	{
		iLog("Finalization Module");

		//OnFinish module
		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			// finish
			it->GetObject()->OnFinish();
		}

		// clear all module
		mModules->Clear();
	}

	//-------------------------------------------------------
	// LoadModules
	//-------------------------------------------------------
	Array<TModuleManager::RefModule> TModuleManager::LoadModules(Array<String>& modulesName)
	{
		Array<RefModule> retVal = new Array<RefModule>::Create();

		for(Array<String>::Iterator it = modulesName->Begin(), end = modulesName->End(); it!=end; ++it)
		{
			IModule::PInitModuleCall pCall = (IModule::PInitModuleCall)Platform::Win32::GetProcAddress(Platform::Win32::LoadLibraryA(it->Chars()), "__InitModule");
			{
				RefModule newModule(pCall(*this));
				retVal->Add(newModule);
			}
		}
		return retVal;
	}

	//-------------------------------------------------------
	// DoInit
	//-------------------------------------------------------
	void TModuleManager::DoInit()
	{
		// Start Module
		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			it->GetObject()->OnInit();
		}
	}

	//-------------------------------------------------------
	// DoStart
	//-------------------------------------------------------
	void TModuleManager::DoStart()
	{
		// Start Module
		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			it->GetObject()->OnStart();
		}
	}

	//-------------------------------------------------------
	// OnUpdate
	//-------------------------------------------------------
	void TModuleManager::DoUpdate(float dt)
	{
		//update module
		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			it->GetObject()->OnUpdate(dt);
		}
		//update delegate?
	}

	//-------------------------------------------------------
	// SendEvent
	//-------------------------------------------------------
	void TModuleManager::SendEvent(const Event& evnt)
	{
		switch(evnt.GetCode())
		{
		case EventCode::ModuleInit:
			SetModule(evnt.As<ModuleEventInitialize>());
			break;
		}

		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			it->GetObject()->AcceptEvent(evnt);
		}
	}

	//-------------------------------------------------------
	// Active
	//-------------------------------------------------------
	void TModuleManager::Active(bool active)
	{
		for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		{
			it->GetObject()->OnActive(active);
		}
	}

	//-------------------------------------------------------
	// SetModule
	//-------------------------------------------------------
	void TModuleManager::SetModule(const ModuleEventInitialize& evnt)
	{
		switch(evnt.GetInitializeType())
		{
		case ModuleType::CoreSystem:
			mCoreContext = evnt.As<ModuleEventInitializeType<IDK::ICore>>().GetModule();
			break;
		case ModuleType::RenderSystem:
			mRenderContext = evnt.As<ModuleEventInitializeType<IDK::IRenderContext>>().GetModule();
			break;
		}
	}

	//-------------------------------------------------------
	// GetRenderer
	//-------------------------------------------------------
	ref<IDK::IRenderContext> TModuleManager::GetRenderer(void)
	{
		return mRenderContext;
	}

	//-------------------------------------------------------
	// GetCore
	//-------------------------------------------------------
	ref<IDK::ICore> TModuleManager::GetCore(void)
	{
		return mCoreContext;
	}

	//-------------------------------------------------------
	// Lock
	//-------------------------------------------------------
	void TModuleManager::Lock(bool reset)
	{
#if defined(DEBUG) | defined(_DEBUG)
		//iLogDebug("Allocation in Managed");
		//iLogDebug(Convert::ToString(allocationCount)->Chars());
#endif

		mRenderContext->Lock(reset);
		mCoreContext->Lock(reset);
		
		//for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		//{
		//	it->GetObject()->Lock();
		//}
	}

	//-------------------------------------------------------
	// Lock
	//-------------------------------------------------------
	void TModuleManager::Unlock(void)
	{
		mCoreContext->Unlock();
		mRenderContext->Unlock();

		//for(SortList<RefModule>::Iterator it = mModules->Begin(), end = mModules->End(); it!=end; ++it)
		//{
		//	it->GetObject()->Unlock();
		//}
	}
}